/*=============================================================================
    Copyright (c) 2001-2003 Hartmut Kaiser
    http://spirit.sourceforge.net/

    Use, modification and distribution is subject to the Boost Software
    License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
    http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/
///////////////////////////////////////////////////////////////////////////////
// This sample shows the usage of the list_p utility parser
//  1. parsing a simple ',' delimited list w/o item formatting
//  2. parsing a CSV list (comma separated values - strings, integers or reals)
//  3. parsing a token list (token separated values - strings, integers or
//     reals)
// with an action parser directly attached to the item part of the list_p
// generated parser

#include <string>
#include <iostream>
#include <cassert>
#include <vector>

#include <boost/spirit/include/classic_core.hpp>
#include <boost/spirit/include/classic_confix.hpp>
#include <boost/spirit/include/classic_lists.hpp>
#include <boost/spirit/include/classic_escape_char.hpp>

///////////////////////////////////////////////////////////////////////////////
using namespace std;
using namespace BOOST_SPIRIT_CLASSIC_NS;

///////////////////////////////////////////////////////////////////////////////
// actor, attached to the list_p parser
class list_actor
{
public:
    list_actor (std::vector<std::string> &vec_) : vec(vec_) {}

    // The following operator() is called by the action parser generated by
    // attaching this actor to a list_p generated list parser.

    template <typename ActionIterT>
    void operator() (ActionIterT const &first, ActionIterT const &last) const
    {
        vec.push_back(std::string(first, last-first));
    }

private:
    std::vector<std::string> &vec;
};

///////////////////////////////////////////////////////////////////////////////
// main entry point
int main ()
{
    // 1. parsing a simple ',' delimited list w/o item formatting
    char const*                 plist_wo_item = "element1,element2,element3";
    rule<>                      list_wo_item;
    std::vector<std::string>    vec_list;

    list_wo_item =
            list_p[push_back_a(vec_list)]
        ;

    parse_info<> result = parse (plist_wo_item, list_wo_item);

    cout << "-----------------------------------------------------------------"
        << endl;

    if (result.hit)
    {
        cout
            << "Parsing simple list" << endl
            << "\t" << plist_wo_item << endl
            << "Parsed successfully!" << endl << endl;

        cout
            << "Actor was called " << (int)vec_list.size()
            << " times: " << endl;

        cout
            << "Results got from the list parser:" << endl;
        for (std::vector<std::string>::iterator it = vec_list.begin();
             it != vec_list.end(); ++it)
        {
            cout << *it << endl;
        }
    }
    else
    {
        cout << "Failed to parse simple list!" << endl;
    }

    cout << endl;

    // 2. parsing a CSV list (comma separated values - strings, integers or
    // reals)
    char const *plist_csv = "\"string\",\"string with an embedded \\\"\","
        "12345,0.12345e4,,2";
    rule<> list_csv, list_csv_item;
    std::vector<std::string> vec_item;

    vec_list.clear();

    list_csv_item =
        !(
                confix_p('\"', *c_escape_ch_p, '\"')
            |   longest_d[real_p | int_p]
        );

    list_csv =
            list_p(
                list_csv_item[push_back_a(vec_item)],
                ','
            )[push_back_a(vec_list)]
        ;

    result = parse (plist_csv, list_csv);

    cout << "-----------------------------------------------------------------"
        << endl;
    if (result.hit)
    {
        cout
            << "Parsing CSV list (comma separated values) " << endl
            << "\t" << plist_csv << endl
            << "Parsed successfully!" << endl << endl;

        if (result.full)
        {
            cout << "Matched " << (int)vec_list.size() <<
                " list elements (full list): " << endl;
        }
        else
        {
            cout << "Matched " << (int)vec_list.size() <<
                " list elements: " << endl;
        }

        cout << "The list parser matched:" << endl;
        for (std::vector<std::string>::iterator itl = vec_list.begin();
                itl != vec_list.end(); ++itl)
        {
            cout << *itl << endl;
        }

        cout << endl << "Item(s) got directly from the item parser:" << endl;
        for (std::vector<std::string>::iterator it = vec_item.begin();
                it != vec_item.end(); ++it)
        {
            cout << *it << endl;
        }

    }
    else
    {
        cout << "Failed to parse CSV list!" << endl;
    }

    cout << endl;

    // 3. parsing a token list (token separated values - strings, integers or
    // reals) with an action parser directly attached to the item part of the
    // list_p generated parser
    char const *plist_csv_direct = "\"string\"<par>\"string with an embedded "
        "\\\"\"<par>12345<par>0.12345e4";
    rule<> list_csv_direct, list_csv_direct_item;

    vec_list.clear();
    vec_item.clear();

    // Note: the list parser is here generated through the list_p.direct()
    // generator function. This inhibits re-attachment of the item_actor_direct
    // during parser construction (see: comment in utility/lists.hpp)
    list_csv_direct_item =
            confix_p('\"', *c_escape_ch_p, '\"')
        |   longest_d[real_p | int_p]
        ;

    list_csv_direct =
            list_p.direct(
                (*list_csv_direct_item)[list_actor(vec_item)],
                "<par>"
            )[list_actor(vec_list)]
        ;

    result = parse (plist_csv_direct, list_csv_direct);

    cout << "-----------------------------------------------------------------"
        << endl;
    if (result.hit)
    {
        cout
            << "Parsing CSV list (comma separated values)" << endl
            << "The list parser was generated with 'list_p.direct()'" << endl
            << "\t" << plist_csv_direct << endl
            << "Parsed successfully!" << endl << endl;

        if (result.full)
        {
            cout << "Matched " << vec_list.size() <<
                " list elements (full list): " << endl;
        }
        else
        {
            cout << "Matched " << vec_list.size() <<
                " list elements: " << endl;
        }

        cout << "The list parser matched:" << endl;
        for (std::vector<std::string>::iterator itl = vec_list.begin();
                itl != vec_list.end(); ++itl)
        {
            cout << *itl << endl;
        }

        cout << endl << "Items got directly from the item parser:" << endl;
        for (std::vector<std::string>::iterator it = vec_item.begin();
                it != vec_item.end(); ++it)
        {
            cout << *it << endl;
        }

    }
    else
    {
        cout << "Failed to parse CSV list!" << endl;
    }

    cout << endl;

    return 0;
}
